package com.zwp.base.base

import android.os.Bundle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zwp.base.entity.ShowDialogEntity
import com.zwp.base.event.SingleLiveEvent
import com.zwp.base.exception.DealException
import com.zwp.base.state.EmptyState
import com.zwp.base.state.StateModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

open class BaseViewModel : ViewModel() {

    val uc = UIChangeLiveData()

    val stateModel by lazy {
        StateModel().apply {
            reloadClick = { onReloadPressed() }
            backClick = { onBackPressed() }
        }
    }

    fun onReloadPressed() {
        uc.onReloadPressedEvent.call()
    }

    open fun finish() {
        uc.finishEvent.call()
    }

    open fun onBackPressed() {
        uc.onBackPressedEvent.call()
    }

    fun startActivity(clazz: Class<*>, bundle: Bundle? = null) {
        val params = hashMapOf<String, Any>()
        params[ParameterField.CLASS] = clazz
        if (bundle != null) {
            params[ParameterField.BUNDLE] = bundle
        }
        uc.startActivityEvent.postValue(params)
    }

    class UIChangeLiveData {
        val finishEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<Void>() }
        val onBackPressedEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<Void>() }
        val startActivityEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<Map<String, Any>>() }
        val showDialogEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<String>() }
        val showLoadingDialogEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<Void>() }
        val showCancelableDialogEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<ShowDialogEntity>() }
        val dismissDialogEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<Void>() }
        val onReloadPressedEvent by lazy(LazyThreadSafetyMode.NONE) { SingleLiveEvent<Void>() }
    }

    object ParameterField {
        const val CLASS = "CLASS"
        const val CANONICAL_NAME = "CANONICAL_NAME"
        const val BUNDLE = "BUNDLE"
    }

    fun <T> launchWithFlow(block: suspend () -> T) =
        flow {
            emit(block())
        }
            .flowOn(Dispatchers.IO)
            .onStart {
                uc.showLoadingDialogEvent.call()
            }.onCompletion {
                uc.dismissDialogEvent.call()
            }.catch { e ->
                uc.dismissDialogEvent.call()
                stateModel.emptyState = EmptyState.NET_ERROR
                val exception = DealException.handlerException(e)
                stateModel.loadingContent.set(exception.msg)
            }


    fun <T> launchWithFlowAndCollect(block: suspend () -> T, collectBlock: () -> Unit) =
        viewModelScope.launch {
            launchWithFlow { block() }
                .collect {
                    collectBlock()
                }
        }
}